package io.yyxx.boot.business.service.impl;

import com.google.common.util.concurrent.RateLimiter;
import io.yyxx.boot.business.entity.billDataEntity.BillQueryParams;
import io.yyxx.boot.util.CorpAuthApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;

@Component
@Slf4j
public class MyStart {

    @Value("${ali.strip.appKey}")
    private String appKey;

    @Autowired
    private CorpAuthApi corpAuthApi;

    @Resource
    private DataSyncService dataSyncService;

    @Resource
    private Train train;

    @Resource
    private Hotel hotel;

    @Resource
    private Flight flight;

    @Resource
    private Car car;

    // 每秒最多执行多少次任务,设置最大QPS
    private static final double QPS_LIMIT = 5;
    // 记录任务数量和起始时间
    private static int taskCount = 0;
    // 记录任务数量和起始时间
    private static long startTime = System.currentTimeMillis();

    public void pullForAlitrip() {
        // 1.获取当前时间
        LocalDateTime now = LocalDateTime.now();

        // 1.1计算结束时间，当前时间减去一小时
        LocalDateTime endTime = now.minusHours(1);

        // 1.2计算开始时间，昨天的同一时间
        LocalDateTime startTime = endTime.minusDays(1);

        // 1.3计算开始时间和结束时间之间的时间差
        Duration duration = Duration.between(startTime, endTime);
        // 2. 校验时间范围（必须≤24小时）
        if (duration.toHours() > 24) {
            log.info("开始时间和结束时间之间的间隔超过了 24 小时，请检查！");
        } else {
            log.info("开始时间和结束时间之间的间隔未超过 24 小时。");
        }

        // 格式化时间，使用指定的格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedStartTime = startTime.format(formatter);
        log.info("查询记账数据起始时间: {}", formattedStartTime);

        String formattedEndTime = endTime.format(formatter);
        log.info("查询记账数据截止时间: {}", formattedEndTime);

        // 3. Token管理（有效期2小时）
        String corpToken = corpAuthApi.getToken();

        // 4. 初始化查询参数
        BillQueryParams params = new BillQueryParams();
        params.setScrollMod(true); // 关闭滚动模式
        params.setPageNo(1); // 起始页码
        params.setPageSize(100); // 使用最大分页尺寸
        params.setPeriodStart("2025-01-01"); //设置查询开始时间
        params.setPeriodEnd(formattedEndTime); //设置查询结束时间
        //从阿里商旅获取数据，并保存到数据库中
        dataSyncService.syncDataProcess(params, appKey, corpToken);
    }

    // 2. 多线程执行方法
    public void saveToYiDa() {
        // 创建一个 RateLimiter 实例，限制每秒的请求数为 5
        RateLimiter rateLimiter = RateLimiter.create(QPS_LIMIT);
        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(4);
        // 提交任务到线程池
        executor.submit(() -> executeTask(rateLimiter, this::saveTrainBill));
        executor.submit(() -> executeTask(rateLimiter, this::saveHotelBill));
        executor.submit(() -> executeTask(rateLimiter, this::saveFlightBill));
        executor.submit(() -> executeTask(rateLimiter, this::saveCarBill));

        // 关闭线程池并等待所有任务完成
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            log.error("向宜搭发送数据时出现异常,线程池关闭失败,强制关闭", e);
        }
        log.info("已执行完所有（向宜搭发送数据时）的线程任务");
    }

    //确保向宜搭发送数据QPS不超过 5 !!
    private void executeTask(RateLimiter rateLimiter, Runnable task) {
        try {
            // 从 RateLimiter 获取许可，若没有可用许可会阻塞直到有许可
            rateLimiter.acquire();
            task.run();
            recordQPS();
        } catch (Exception e) {
            log.error("执行宜搭数据保存任务时发生异常", e);
        }
    }

    //记录并输出当前的QPS
    private synchronized void recordQPS() {
        taskCount++;
        long currentTime = System.currentTimeMillis();
        if (currentTime - startTime >= 1000) {
            double qps = (double) taskCount / ((currentTime - startTime) / 1000.0);
            log.info("当前 QPS: {}", qps);
            taskCount = 0;
            startTime = currentTime;
        }
    }

    //  定义原子任务方法 (添加异常处理)
    private void saveTrainBill() {
        try {
            train.saveTrainBillToYiDa();
        } catch (Exception e) {
            log.error("火车账单保存失败", e);
        }
    }

    private void saveHotelBill() {
        try {
            hotel.saveHotelBillToYiDa();
        } catch (Exception e) {
            log.error("酒店账单保存失败", e);
        }
    }

    private void saveFlightBill() {
        try {
            flight.saveTrainBillToYiDa();
        } catch (Exception e) {
            log.error("航班账单保存失败", e);
        }
    }

    private void saveCarBill() {
        try {
            car.saveTrainBillToYiDa();
        } catch (Exception e) {
            log.error("用车账单保存失败", e);
        }
    }
}

